use std::path::PathBuf;

use crate::{entity::Entity, environment::ThemeMode, layout::cache::GeoChanged};
use vizia_input::{Code, Key, MouseButton};
use vizia_style::CursorIcon;
use vizia_window::{WindowPosition, WindowSize};

#[derive(Debug, Clone)]
/// Data associated with a drop event.
pub enum DropData {
    /// Path to a dropped file.
    File(PathBuf),
    ///  Entity ID of a dropped entity.
    Id(Entity),
}

impl From<Entity> for DropData {
    fn from(value: Entity) -> Self {
        DropData::Id(value)
    }
}

impl From<PathBuf> for DropData {
    fn from(value: PathBuf) -> Self {
        DropData::File(value)
    }
}

/// Events generated by the application in response to OS events as well as events that can be used
/// to set properties of the window.
#[derive(Debug, Clone)]
pub enum WindowEvent {
    /// Emitted when a window is closed. Can also be emitted by a view or model to close the window.
    WindowClose,
    /// Emitted when the window is moved.
    WindowMoved(WindowPosition),
    /// Emitted when a file is dragged and then dropped onto the window.
    Drop(DropData),
    /// Emitted when a mouse button is double clicked.
    MouseDoubleClick(MouseButton),
    /// Emitted when a mouse button is triple clicked
    MouseTripleClick(MouseButton),
    /// Emitted when a mouse button is pressed
    MouseDown(MouseButton),
    /// Emitted when a mouse button is released.
    MouseUp(MouseButton),
    /// Emitted when the primary mouse button or trigger key is pressed and then released on a view
    Press {
        /// Whether the press event was triggered by the mouse.
        mouse: bool,
    },
    /// Emitted when the primary mouse button or trigger key is pressed on a view
    PressDown {
        /// Whether the press down event was triggered by the mouse.
        mouse: bool,
    },
    /// Emitted when the mouse cursor is moved
    MouseMove(f32, f32),
    /// Emitted when the mouse scroll wheel is scrolled.
    MouseScroll(f32, f32),
    /// Emitted when the mouse cursor enters the bounding box of an entity.
    MouseOver,
    /// Emitted when the mouse cursor leaves the bounding box of an entity.
    MouseOut,
    /// Emitted when the mouse cursor enters an entity.
    MouseEnter,
    /// Emitted when the mouse cursor leaves an entity.
    MouseLeave,
    /// Emitted when an entity gains keyboard focus.
    FocusIn,
    /// Emitted when an entity loses keyboard focus.
    FocusOut,
    /// Emitted when an entity's focus visibility has changed.
    FocusVisibility(bool),
    /// Emitted when the window gains or loses focus
    WindowFocused(bool),
    /// Emitted when a character is typed.
    CharInput(char),
    /// Emitted when the input method (IME) is activated or deactivated.
    ImeActivate(bool),
    /// Emitted when an input method (IME) commits a string.
    ImeCommit(String),
    /// Emitted when an input method (IME) changes the preedit string.
    ImePreedit(String, Option<(usize, usize)>),
    /// Emitted when the input method (IME) area needs to be updated.
    SetImeCursorArea((u32, u32), (u32, u32)),
    /// Emitted when a keyboard key is pressed.
    KeyDown(Code, Option<Key>),
    /// Emitted when a keyboard key is released.
    KeyUp(Code, Option<Key>),
    /// Emited when the system window theme has changed.
    ThemeChanged(ThemeMode),
    /// Sets the mouse cursor icon.
    SetCursor(CursorIcon),
    /// Grabs the mouse cursor, preventing it from leaving the window.
    GrabCursor(bool),
    /// Sets the (x,y) position of the mouse cursor in window coordinates.
    SetCursorPosition(u32, u32),
    /// Sets the title of the window.
    SetTitle(String),
    /// Sets the size of the window.
    SetSize(WindowSize),
    /// Sets the position of the window.
    SetPosition(WindowPosition),
    /// Sets the maximum size of the window.
    SetMaxSize(Option<WindowSize>),
    /// Sets the minimum size of the window.
    SetMinSize(Option<WindowSize>),
    /// Sets whether the window is resizable.
    SetResizable(bool),
    /// Sets whether the window is minimized.
    SetMinimized(bool),
    /// Sets whether the window is maximized.
    SetMaximized(bool),
    /// Sets whether the window is visible.
    SetVisible(bool),
    /// Sets whether the window has decorations.
    SetDecorations(bool),
    /// Sets whether the window remains on top of other windows.
    SetAlwaysOnTop(bool),
    /// Emitted when mouse events have been captured.
    MouseCaptureEvent,
    /// Emitted when mouse events have been released.
    MouseCaptureOutEvent,
    // TODO: check if this includes margins + borders.
    /// Emitted when an entity changes position or size.
    GeometryChanged(GeoChanged),
    /// Requests a redraw of the window contents.
    Redraw,
    /// Request a restyle.
    Restyle,
    /// Requests a relayout.
    Relayout,
    /// Move keyboard focus to the next navigable view.
    FocusNext,
    /// Move keyboard focus to the previous navigable view.
    FocusPrev,
    /// Prints the debug message to the console.
    Debug(String),
    /// Represents an action requested by an accessibility technology.
    ActionRequest(accesskit::ActionRequest),
    /// Reloads all application stylesheets.
    ReloadStyles,
    /// Enables or disabled mouse and keyboard input to the window.
    SetEnabled(bool),
    /// Puts the window in a drag state.
    DragWindow,

    /// Emitted when the window is destroyed.
    Destroyed,
}
